﻿#region Header
// ------------------------ Licence / Copyright ------------------------
// 
// ScrumTable for Scrum Meeting Support
// Copyright © HSR - Hochschule für Technik Rapperswil
// All Rights Reserved
// 
// Author:
//  Michael Gfeller Silvan Gehrig Patrick Boos
// 
// ---------------------------------------------------------------------
#endregion

#region Usings

using System;
using System.ComponentModel;
using ScrumTable.Common;
using ScrumTable.DL.Data.Schema;

#endregion

namespace ScrumTable.DL.Data.Common
{
    /// <summary>
    /// This class specifies the base data object. Each data object may contain
    /// multiple values which can be retrieved with the indexer. A data object
    /// has a unique identifier and an order index, which is given by the
    /// underlying system.
    /// The implemented properties are specified in their corresponding
    /// DataObject Schema descriptions.
    /// </summary>
    /// <remarks>The implementation of the data object class follows the Anything pattern.</remarks>
    public interface IDataObject : IDisposableObject, INotifyPropertyChanged, INotifyPropertyChanging
    {
        #region Properties
        //--------------------------------------------------------------------
        // Properties
        //--------------------------------------------------------------------

        /// <summary>
        /// Gets the ID of the current data object.
        /// </summary>
        string Id { get; }

        /// <summary>
        /// Gets the unique id of the underlying back end system identity.
        /// </summary>
        string BackEndId { get; }

        /// <summary>
        /// Gets the underlying system order index. This property can be used
        /// to output the elements in the order given by the data connector.
        /// </summary>
        double OrderIndex { get; }

        /// <summary>
        /// Gets true if the changes have been synchronized with the back-end system.
        /// </summary>
        bool IsSynchronized { get; }

        /// <summary>
        /// Gets or sets a value of the current data object. The data format
        /// must be specified in a separate document in order to support
        /// later updates and avoid broken interfaces.
        /// </summary>
        /// <param name="name">Name of the value to access.</param>
        /// <returns>Returns the retrieved data object.</returns>
        object this[string name] { get; set; }

        /// <summary>
        /// Gets the corresponding data schema (e.g. UserStorySchema / TaskSchema / ...).
        /// </summary>
        SchemaBase Schema { get; }

        #endregion

        #region Methods
        //--------------------------------------------------------------------
        // Methods
        //--------------------------------------------------------------------

        /// <summary>
        /// Gets the state (with all internal information and data)
        /// of the current data object.
        /// </summary>
        IDataObjectState ExportState();

        /// <summary>
        /// Gets the state (with all internal information and data)
        /// of the current data object. This procedure will store only
        /// the fields given in the value names list into the state.
        /// </summary>
        /// <param name="valueNames">Specifies a list of value names which should be stored into the state.</param>
        IDataObjectState ExportState(params string[] valueNames);

        /// <summary>
        /// Gets the state (with all internal information and data)
        /// of the current data object.
        /// </summary>
        /// <param name="toImport">Specifies the state to import.</param>
        /// <param name="beforeValueSet">Specifies the action which should be executed before a value is stored back to the data object.</param>
        /// <param name="afterValueSet">Specifies the action which should be executed after a value is stored back to the data object.</param>
        /// <returns>
        /// Returns the changes between the current and the imported state.
        /// </returns>
        void ImportState(IDataObjectState toImport, Action<SchemaBase> beforeValueSet, Action<SchemaBase> afterValueSet);

        /// <summary>
        /// Gets the state (with all internal information and data)
        /// of the current data object.
        /// </summary>
        /// <param name="toImport">Specifies the state to import.</param>
        /// <returns>
        /// Returns the changes between the current and the imported state.
        /// </returns>
        void ImportState(IDataObjectState toImport);

        /// <summary>
        /// Sets the field with the given name. Fires an event before writing
        /// the value and after writing the value.
        /// </summary>
        /// <param name="name">Name of the field to write.</param>
        /// <param name="newValue">The new value to write. If the old value is the same to the new value it will not be overwritten.</param>
        /// <param name="beforeWriting">The action executed before writing the value. This argument may be null.</param>
        /// <param name="afterWriting">The action executed after writing the value. This argument may be null.</param>
        void SetData(string name, object newValue, Action beforeWriting, Action afterWriting);

        /// <summary>
        /// Sets the field with the given name. Fires an event before writing
        /// the value and after writing the value. If the newValue is null,
        /// you will receive an argument null exception.
        /// </summary>
        /// <param name="name">Name of the field to write.</param>
        /// <param name="newValue">The new value to write. If the old value is the same to the new value it will not be overwritten.</param>
        /// <param name="beforeWriting">The action executed before writing the value. This argument may be null.</param>
        /// <param name="afterWriting">The action executed after writing the value. This argument may be null.</param>
        void SetDataNotNull(string name, object newValue, Action beforeWriting, Action afterWriting);

        /// <summary>
        /// Gets the data associated with the specified name.
        /// </summary>
        /// <typeparam name="T">Type of the returning value.</typeparam>
        /// <param name="name">The name of the field to retreive.</param>
        /// <returns>Returns either the retrieved value or a default value.</returns>
        T GetData<T>(string name);

        /// <summary>
        /// Gets the data associated with the specified name.
        /// </summary>
        /// <typeparam name="T">Type of the returning value.</typeparam>
        /// <param name="name">The name of the field to retreive.</param>
        /// <param name="defaultValue">Specifies the default value.</param>
        /// <returns>Returns either the retrieved value or a default value.</returns>
        T GetData<T>(string name, T defaultValue);

        /// <summary>
        /// Gets the data associated with the specified name.
        /// </summary>
        /// <typeparam name="T">Type of the returning value.</typeparam>
        /// <param name="name">The name of the field to retreive.</param>
        /// <param name="converter">Converter which is used to convert a value into the expected type.</param>
        /// <returns>Returns either the retrieved value or a default value.</returns>
        T GetData<T>(string name, Func<object, T> converter);

        /// <summary>
        /// Gets the data associated with the specified name.
        /// </summary>
        /// <typeparam name="T">Type of the returning value.</typeparam>
        /// <param name="name">The name of the field to retreive.</param>
        /// <param name="converter">Converter which is used to convert a value into the expected type.</param>
        /// <param name="defaultValue">Specifies the default value.</param>
        /// <returns>Returns either the retrieved value or a default value.</returns>
        T GetData<T>(string name, Func<object, T> converter, T defaultValue);

        #endregion

        #region Events
        //--------------------------------------------------------------------
        // Events
        //--------------------------------------------------------------------

        #endregion
    }
}